<?php

declare(strict_types=1);

namespace SixShop\Wangdian\Http;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Exception\RequestException;
use Psr\Http\Client\ClientInterface;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
use SixShop\Wangdian\Config\Config;
use SixShop\Wangdian\Exception\HttpException;

/**
 * HTTP client wrapper for making API requests
 */
class HttpClient
{
    private readonly ClientInterface $client;
    private readonly LoggerInterface $logger;

    public function __construct(
        private readonly Config $config,
        ?ClientInterface $client = null,
        ?LoggerInterface $logger = null
    ) {
        $this->client = $client ?? new Client([
            'timeout' => $this->config->timeout,
            'verify' => !$this->config->isSandbox(), // Disable SSL verification for sandbox
            'headers' => [
                'User-Agent' => 'SixShop-Wangdian-SDK/1.0',
                'Accept' => 'application/json',
            ],
        ]);

        $this->logger = $logger ?? new NullLogger();
    }

    /**
     * Make a POST request to the API
     */
    public function post(string $endpoint, array $data = []): array
    {
        $url = $this->config->getEndpoint($endpoint);

        try {
            $this->logger->info('Making API request', [
                'url' => $url,
                'data_keys' => array_keys($data),
            ]);

            $response = $this->client->request('POST', $url, [
                'form_params' => $data,
                'headers' => [
                    'Content-Type' => 'application/x-www-form-urlencoded',
                ],
            ]);

            $statusCode = $response->getStatusCode();
            $body = $response->getBody()->getContents();

            $this->logger->info('API response received', [
                'status_code' => $statusCode,
                'response_length' => strlen($body),
            ]);

            if ($statusCode !== 200) {
                throw new HttpException(
                    message: "HTTP request failed with status code: {$statusCode}",
                    httpStatusCode: $statusCode,
                    context: ['response_body' => $body]
                );
            }

            return $this->parseResponse($body);

        } catch (RequestException $e) {
            $this->logger->error('HTTP request failed', [
                'url' => $url,
                'error' => $e->getMessage(),
            ]);

            throw new HttpException(
                message: 'HTTP request failed: ' . $e->getMessage(),
                previous: $e,
                httpStatusCode: $e->getResponse()?->getStatusCode(),
                context: ['url' => $url, 'data' => $data]
            );
        } catch (GuzzleException $e) {
            $this->logger->error('Guzzle exception', [
                'url' => $url,
                'error' => $e->getMessage(),
            ]);

            throw new HttpException(
                message: 'HTTP client error: ' . $e->getMessage(),
                previous: $e,
                context: ['url' => $url, 'data' => $data]
            );
        }
    }

    /**
     * Parse JSON response
     */
    private function parseResponse(string $body): array
    {
        if (empty($body)) {
            throw new HttpException('Empty response body received');
        }

        $decoded = json_decode($body, true);

        if (json_last_error() !== JSON_ERROR_NONE) {
            $this->logger->error('Failed to parse JSON response', [
                'json_error' => json_last_error_msg(),
                'response_body' => $this->config->debug ? $body : '[hidden]',
            ]);

            throw new HttpException(
                message: 'Failed to parse JSON response: ' . json_last_error_msg(),
                context: ['response_body' => $body]
            );
        }

        return $decoded;
    }
}